﻿
// -----------------------------------------------------------------------
// Copyright (c) David Kean. All rights reserved.
// -----------------------------------------------------------------------
extern alias pcl;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using System;
using System.Linq.Expressions;

using pcl::System.Diagnostics;
using pcl::System.Adaptation;
using pcl::System.Diagnostics.Adaptation;

namespace Portable.Security.Cryptography
{
    [TestClass]
    public class StopwatchTests
    {
        [TestMethod]
        public void Elapsed_ReturnsUnderlyingStopwatchElapsed()
        {
            var elapsed = TimeSpan.FromDays(1);

            var watch = CreateStopwatchOverridding(w => w.Elapsed, elapsed);

            Assert.AreEqual(elapsed, watch.Elapsed);
        }

        [TestMethod]
        public void ElapsedMilliseconds_ReturnsUnderlyingStopwatchElapsedMilliseconds()
        {
            var elapsedMilliseconds = 1000;

            var watch = CreateStopwatchOverridding(w => w.ElapsedMilliseconds, elapsedMilliseconds);

            Assert.AreEqual(elapsedMilliseconds, watch.ElapsedMilliseconds);
        }

        [TestMethod]
        public void ElapsedTicks_ReturnsUnderlyingStopwatchElapsedTicks()
        {
            var elapsedTicks = 10;

            var watch = CreateStopwatchOverridding(w => w.ElapsedTicks, elapsedTicks);

            Assert.AreEqual(elapsedTicks, watch.ElapsedTicks);
        }

        [TestMethod]
        public void IsRunning_ReturnsUnderlyingStopwatchElapsedTicks()
        {
            var isRunning = true;

            var watch = CreateStopwatchOverridding(w => w.IsRunning, isRunning);

            Assert.AreEqual(isRunning, watch.IsRunning);
        }

        [TestMethod]
        public void IsHighResolution_ReturnsUnderlyingStopwatchIsHighResolution()
        {
            var isHighResolution = true;
            var adapter = IStopwatchStaticFactory.Override(w => w.IsHighResolution, isHighResolution);
            var resolver = IAdapterResolverFactory.OverrideResolve(type => adapter);
            PlatformAdapter.SetResolver(resolver);

            Assert.AreEqual(Stopwatch.IsHighResolution, isHighResolution);
        }

        [TestMethod]
        public void Frequency_ReturnsUnderlyingStopwatchIsFrequency()
        {
            var frequency = 10;
            var adapter = IStopwatchStaticFactory.Override(w => w.Frequency, frequency);
            var resolver = IAdapterResolverFactory.OverrideResolve(type => adapter);
            PlatformAdapter.SetResolver(resolver);

            Assert.AreEqual(Stopwatch.Frequency, frequency);
        }

        [TestMethod]
        public void GetTimestamp_ReturnsUnderlyingStopwatchGetTimestamp()
        {
            var timestamp = 10;
            var adapter = IStopwatchStaticFactory.Override(w => w.GetTimestamp(), timestamp);
            var resolver = IAdapterResolverFactory.OverrideResolve(type => adapter);
            PlatformAdapter.SetResolver(resolver);

            Assert.AreEqual(Stopwatch.GetTimestamp(), timestamp);
        }

        [TestMethod]
        public void StartNew_CallsStartOnReturnedStopwatch()
        {
            int callCount = 0;
            var adapter = IStopwatchFactory.Override(a => a.Start(), () => { callCount++; });
            var factory = IStopwatchAdapterFactory.Override(a => a.Create(), adapter);
            var resolver = IAdapterResolverFactory.OverrideResolve(type => factory);
            PlatformAdapter.SetResolver(resolver);
            var stopwatch = Stopwatch.StartNew();

            Assert.AreEqual(callCount, 1);
        }

        [TestMethod]
        public void Start_CallsUnderlyingStopwatchStart()
        {
            int callCount = 0;
            var adapter = IStopwatchFactory.Override(a => a.Start(), () => { callCount++; });
            var factory = IStopwatchAdapterFactory.Override(a => a.Create(), adapter);
            var resolver = IAdapterResolverFactory.OverrideResolve(type => factory);
            PlatformAdapter.SetResolver(resolver);
            var stopwatch = new Stopwatch();

            stopwatch.Start();

            Assert.AreEqual(callCount, 1);
        }

        [TestMethod]
        public void Reset_CallsUnderlyingStopwatchReset()
        {
            int callCount = 0;
            var adapter = IStopwatchFactory.Override(a => a.Reset(), () => { callCount++; });
            var factory = IStopwatchAdapterFactory.Override(a => a.Create(), adapter);
            var resolver = IAdapterResolverFactory.OverrideResolve(type => factory);
            PlatformAdapter.SetResolver(resolver);
            var stopwatch = new Stopwatch();

            stopwatch.Reset();

            Assert.AreEqual(callCount, 1);
        }

        [TestMethod]
        public void Restart_CallsUnderlyingStopwatchRestart()
        {
            int callCount = 0;
            var adapter = IStopwatchFactory.Override(a => a.Restart(), () => { callCount++; });
            var factory = IStopwatchAdapterFactory.Override(a => a.Create(), adapter);
            var resolver = IAdapterResolverFactory.OverrideResolve(type => factory);
            PlatformAdapter.SetResolver(resolver);
            var stopwatch = new Stopwatch();

            stopwatch.Restart();

            Assert.AreEqual(callCount, 1);
        }

        [TestMethod]
        public void Stop_CallsUnderlyingStopwatchStop()
        {
            int callCount = 0;
            var adapter = IStopwatchFactory.Override(a => a.Stop(), () => { callCount++; });
            var factory = IStopwatchAdapterFactory.Override(a => a.Create(), adapter);
            var resolver = IAdapterResolverFactory.OverrideResolve(type => factory);
            PlatformAdapter.SetResolver(resolver);
            var stopwatch = new Stopwatch();

            stopwatch.Stop();

            Assert.AreEqual(callCount, 1);
        }

        private static Stopwatch CreateStopwatchOverridding<TResult>(Expression<Func<IStopwatch, TResult>> action, TResult value)
        {
            var adapter = IStopwatchFactory.Override(action, value);
            var factory = IStopwatchAdapterFactory.Override(a => a.Create(), adapter);
            var resolver = IAdapterResolverFactory.OverrideResolve(type => factory);
            PlatformAdapter.SetResolver(resolver);

            var watch = new Stopwatch();
            return watch;
        }
    }
}
